package org.xtext.runtime.teleoreactive;

import org.xtext.runtime.formula.Predicate;
import org.xtext.runtime.interpreter.Agent;
import org.xtext.runtime.interpreter.FailedActionException;
import org.xtext.runtime.interpreter.NoSuchActionException;
import org.xtext.runtime.library.LibraryWrapper;
import org.xtext.runtime.util.Bindings;
import org.xtext.runtime.util.EvaluateTermsVisitor;

public class TRLibraryAction implements ITRAction {
	private String module;
	private Predicate action;
	private int state = 0;
	
	private class Executor implements Runnable {
		Agent agent;
		LibraryWrapper wrapper;

		public Executor(Agent agent, LibraryWrapper wrapper) {
			this.wrapper = wrapper;
			this.agent = agent;
		}

		@Override
		public void run() {
			boolean result = false;
			try {
				result = wrapper.invokeAction((Predicate) action.accept(new EvaluateTermsVisitor(agent)));
			} catch (FailedActionException e) {
				e.printStackTrace();
			} catch (NoSuchActionException e1) {
				e1.printStackTrace();
				state = 2;
				return;
			}
			
			
			if (result) {
				agent.logAction(module + "." + action + " [SUCCESS]");
				state = 0;
			} else {
				agent.logAction(module + "." + action + " [FAILED]");
				state = 2;
			}
		}
	}
	
	public TRLibraryAction(String module, Predicate action) {
		this.module = module;
		this.action = action;
	}
	
	public String toString() {
		return module + "." + action;
	}
	
	@Override
	public boolean handle(Agent agent) {
		switch (state) {
		case 0:
			LibraryWrapper wrapper = agent.getLibrary(module);
			if (wrapper == null) {
				System.err.println(toString() + " [NO SUCH LIBRARY: " + module + "]");
				agent.logAction(toString() + " [NO SUCH LIBRARY: " + module + "]");
				return false;
			}
			
			new Thread(new Executor(agent, wrapper), module + "." + action).start();
			state = 1;
			return true;
		case 1:
			return true;
		case 2:
			return false;
		}
		return false;
	}

	@Override
	public TRLibraryAction apply(Bindings bindings) {
		return new TRLibraryAction(module, action.copy().apply(bindings));
	}

	@Override
	public ITRAction copy() {
		return new TRLibraryAction(module, action.copy());
	}

}
